package util;


/**
 * Stemmer, implementing the Portuguse Porter Stemming Algorithm. The 
 * PortugueseStemmer class transforms a word into its root form. The original paper is in
 * Porter, 1980, An algorithm for suffix stripping, Program, Vol. 14, no. 3, 
 * pp 130-137, See also http://www.tartarus.org/~martin/PorterStemmer
 * <p>
 * The final step "Turn a~, o~ back into ã, õ" is not carried out due to 
 * the previously accentuation removal. The "if the word ends ç remove the cedilla" 
 * rule is carried out at applyAccent() method.  
 * <p>
 * Some stems will be generated wrongly due to the lack of accentuation. For
 * example: "construídas->contru" in which should be "construíd".
 * <p>
 * http://snowball.tartarus.org/ 
 *
 */

public class PortugueseStemmer extends StemmerAnalyzer {
	
	boolean pstep1 = false;
	boolean pstep2 = false;
	boolean pstep3 = false;
	boolean pstep4 = false;
	boolean pstep5 = false;

	/**
	 * Step 1. Standard suffix removal.
	 * @return
	 * @throws Exception
	 */
	private boolean step1() throws Exception {
//		int ctr;
		try {
			//delete if in R2
			String[] list1 = {"eza","ezas","ico","ica","icos","icas","ismo",
					"ismos","avel","ivel","ista","istas","oso","osa","osos","osas",
					"amento","amentos","imento","imentos","adora","ador","acao",
					"adoras","adores","acoes"};
			if (deleteR2(list1, "1")) return true; 
			
			//replace with log if in R2
			String[] list2 = {"logia","logias"};
			if (replaceR2(list2, "log", "2")) return true;
			
			//replace with u if in R2
			String[] list3 = {"ucion","uciones"};
			if (replaceR2(list3, "u", "6")) return true;
			
			//replace with ente if in R2 
			String[] list4 = {"encia","encias"};
			if (replaceR2(list4, "ent", "4")) return true;			
			
			//if preceded by iv, delete if in R2 
			// (and if further preceded by at, delete if in R2), otherwise,
			// if preceded by os, ic or ad, delete if in R2
			String[] list5 = {"ativamente","ivamente","osamente", "icamente","adamente"};
			if (deleteR2(list5, "5")) return true;

			String[] list6 = {"amente"};
			String R1Aux = getR1(); 
			if (deleteR1(list6, "6")) return true;
			//return old value
			setR1(R1Aux);
			if (deleteR2(list6, "7")) return true;
			
			//delete if in R2
			String[] list7 = {"avelmente","ivelmente","mente"};
			if (deleteR2(list7, "8")) return true;			
			
			//delete if in R2 
			//if preceded by abil, ic or iv, delete if in R2 
			String[] list8 = {"abilidade","abilidades","icidade","icidades",
					"ividade", "ividades","idade","idades"};
			if (deleteR2(list8, "9")) return true;
			
			//delete if in R2 
			//if preceded by at, delete if in R2 
			String[] list9 = {"ativa","ativo","ativas","ativos",
					"iva", "ivo","ivas","ivos"};
			if (deleteR2(list9, "10")) return true;			
			
			//replace with ir if in RV and preceded by e 
			String[] list10 = {"eira","eiras"};
			if (replaceRV(list10, "eir", "11")) return true;		
			
		} catch (Exception exc) {
			throw new Exception ("Context: step1 method. Error: "+exc.getMessage());
		}
		return false;
	}
	
	/**
	 * Step 2. Verb suffixes.
	 * @return
	 * @throws Exception
	 */
	private boolean step2() throws Exception {
		try {
			String[] list = {
					"ada","ida","ia","aria","eria","iria","ara","ara","era",
					"era","ira","ava","asse","esse","isse","aste","este","iste",
					"ei","arei","erei","irei","am","iam","ariam","eriam","iriam",
					"aram","eram","iram","avam","em","arem","erem","irem","assem",
					"essem","issem","ado","ido","ando","endo","indo","arao",
					"erao","irao","ar","er","ir","as","adas","idas","ias","arias",
					"erias","irias","aras","aras","eras","eras","iras","avas","es",
					"ardes","erdes","irdes","ares","eres","ires","asses","esses",
					"isses","astes","estes","istes","is","ais","eis","ieis","arieis",
					"erieis","irieis","areis","areis","ereis","ereis","ireis","ireis",
					"asseis","esseis","isseis","aveis","ados","idos","amos","amos",
					"iamos","ariamos","eriamos","iriamos","aramos","eramos","iramos",
					"avamos","emos","aremos","eremos","iremos","assemos","essemos",
					"issemos","imos","armos","ermos","irmos","eu","iu","ou","ira",
					"iras"};
			if (deleteRV(list,"12")) return true;
			
		} catch (Exception exc) {
			throw new Exception ("Context: step2 method. Error: "+exc.getMessage());
		}
		return false;
	}
	
	/**
	 * Step 3. Delete suffix "i" if in RV and preceded by c.
	 * @return
	 * @throws Exception
	 */
	private boolean step3() throws Exception {
		try {
			String[] list = {"ci"};
			if (replaceRV(list, "c", "13")) return true;
		} catch (Exception exc) {
			throw new Exception ("Context: step3 method. Error: "+exc.getMessage());
		}
		return false;
	}

	/**
	 * Step 4. Residual suffix.
	 * @return
	 * @throws Exception
	 */
	private boolean step4() throws Exception {
		try {
			String[] list = {"os","a","i","o"};
			if (deleteRV(list, "14")) return true;			
		} catch (Exception exc) {
			throw new Exception ("Context: step4 method. Error: "+exc.getMessage());
		}
		return false;
	}

	/**
	 * Step 5.
	 * @param pWord
	 * @return
	 * @throws Exception
	 */
	private boolean step5(String pWord) throws Exception {
		boolean result = false;
		try {
			String[] list1 = {"e","\u00E9","\u00EA"};
			if (deleteRV(list1, "15")) {
				if (getRV().endsWith("gu"))
					setRV(getRV().substring(0,getRV().length()-1));
				if (getRV().endsWith("ci"))
					setRV(getRV().substring(0,getRV().length()-1));
				result = true;
			}
			
		} catch (Exception exc) {
			throw new Exception("Context: step5 method. Error: "+exc.getMessage());
		}
		return result;
	}

	/**
	 * Stem the input word returning a different word when the process
	 * was successfully applied.
	 * @param pWord input paramenter.
	 * @return the word modified by the stemming process.
	 * @throws Exception
	 */
	public String stem(String pWord) throws Exception {
		try {
			if (pWord.trim().length() <= 1) return pWord; 
			pstep1 = pstep2 = pstep3 = pstep4 = pstep5 = false;
			String wordAux = "";
			setWord(""); setR1(""); setR2(""); setWordRV(""); setRV("");
			setPr12(false); setPrv(false);
			
			setWord(pWord.trim().toLowerCase());
			setWord(Util.removeAccent(getWord())); 
			wordAux = getWord();
			
			//Call r1, r2 and rv
			rule1(); 
			rule2(); 
			ruleV();
			
			if (isLog()) {
				System.out.println("Word: "+getWord());
				System.out.println("R1: "+getR1());
				System.out.println("R2: "+getR2());
				System.out.println("WordRV: "+getWordRV());
				System.out.println("RV: "+getRV());
			}

			if ((getR1().equalsIgnoreCase("")) &&
				(getR2().equalsIgnoreCase("")) &&
				(getRV().equalsIgnoreCase("")))
				return pWord;
				
			pstep1 = step1();

			//Do step 2 if no ending was removed by step 1.
			if (!pstep1) pstep2 = step2();

			//If the last step to be obeyed - either step 1 or 2 - altered the word,
			//do step 3
			if ((pstep1) || (pstep2)) pstep3 = step3();

			//Alternatively, if neither step 1 nor 2 altered the word, do step 4
			if ((!pstep1) && (!pstep2)) pstep4 = step4();

			//Always do step 5
			pstep5 = step5(wordAux);
			
			if (!pstep1 && !pstep2 && !pstep3 && !pstep4 && !pstep5)
				return pWord;
			else if (isPr12())
				return applyAccent(getWord()+getR1()+getR2(),pWord);
			else
				return applyAccent(getWordRV()+getRV(),pWord);
		} catch (Exception exc) {
			throw new Exception("Context: stem method. Error: "+exc.getMessage());
		}
	}

}

